package com.kinghood.authoritycenter.service.impl;


import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kinghood.authoritycenter.common.model.dao.auth.UserBaseDO;
import com.kinghood.authoritycenter.common.model.dao.authority.AuthorityUserOrganizationRelateDO;
import com.kinghood.authoritycenter.common.model.dao.authority.AuthorityUserRoleRelateDO;
import com.kinghood.authoritycenter.common.model.dto.auth.RegisterReqDTO;
import com.kinghood.authoritycenter.common.model.dto.auth.UserDTO;
import com.kinghood.authoritycenter.common.model.dto.authority.AuthByUserDTO;
import com.kinghood.authoritycenter.common.model.dto.organization.AddUserReqDTO;
import com.kinghood.authoritycenter.common.model.dto.organization.OrganizationQueryReqDTO;
import com.kinghood.authoritycenter.common.model.dto.organization.UpdateUserReqDTO;
import com.kinghood.authoritycenter.common.model.serviceimpl.AuthorityUserOrganizationRelateServiceImpl;
import com.kinghood.authoritycenter.common.model.serviceimpl.AuthorityUserRoleRelateServiceImpl;
import com.kinghood.authoritycenter.common.model.vo.organization.GetUserVO;
import com.kinghood.authoritycenter.common.model.vo.organization.OrganizationUserQueryVO;
import com.kinghood.authoritycenter.common.properties.BaseProperties;
import com.kinghood.authoritycenter.common.util.UserUtil;
import com.kinghood.authoritycenter.dao.auth.UserBaseMapper;
import com.kinghood.authoritycenter.service.IRedisService;
import com.kinghood.authoritycenter.service.IUserBaseService;
import com.kinghood.infrastructure.api.authority.UserRemoteVo;
import com.kinghood.infrastructure.model.KingHoodExceptionUtil;
import com.kinghood.infrastructure.model.constant.CommonConstants;
import com.kinghood.infrastructure.model.constant.redis.RedisConstant;
import com.kinghood.infrastructure.util.base.IdGenUtil;
import com.kinghood.redis.util.RedisManager;
import com.kinghood.sharding.model.KingHoodPageUtil;
import com.kinghood.sharding.model.KingPageResult;
import com.kinghood.sharding.model.PageResponseVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author KingHood
 * @since 2023-12-13
 */
@RequiredArgsConstructor
@Slf4j
@Service
@Validated
public class UserBaseServiceImpl extends ServiceImpl<UserBaseMapper, UserBaseDO> implements IUserBaseService {

    private final RedisManager redisManager;
    private final IRedisService redisService;
    private final BaseProperties baseProperties;
    private final AuthorityUserRoleRelateServiceImpl userRoleRelateService;
    private final AuthorityUserOrganizationRelateServiceImpl userOrganizationRelateService;

    @Override
    public PageResponseVO<OrganizationUserQueryVO> queryUserPage(OrganizationQueryReqDTO in) {

        Page<OrganizationUserQueryVO> page = this.baseMapper.queryPage(KingHoodPageUtil.getPage(in, in), in);
        return KingPageResult.getResult(page);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public UserBaseDO register(RegisterReqDTO in) {
        // 检查账号是否已经存在，停用账号也考虑在内
        UserBaseDO one = new LambdaQueryChainWrapper<UserBaseDO>(this.getBaseMapper())
                .eq(UserBaseDO::getUsername, in.getUsername())
                .eq(UserBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .last("limit 1").one();
        KingHoodExceptionUtil.trueThrows(Objects.nonNull(one), "账号已经存在");

        one = new UserBaseDO();
        one.setId(IdGenUtil.get().nextId());
        one.setUsername(in.getUsername());
        one.setPassword(MD5.create().digestHex16(in.getPassword()));
        one.setStatus(1);
        one.setIsDelete(0);
        one.setCreateTime(new Date());
        one.setUpdateTime(new Date());
        one.setCreateUserId(UserUtil.getUserId());
        one.setUpdateUserId(UserUtil.getUserId());
        this.save(one);

        // 缓存账号信息
        redisService.cacheUser(one.getUsername(),one);

        return one;
    }


    @Override
    public UserDTO checkLogin(String userName, String password) {
        // 查找用户信息
        UserBaseDO userBaseDO = getUserBaseDO(userName);
        // 对比数据
        String digestPassword = MD5.create().digestHex16(password);
        KingHoodExceptionUtil.trueThrows(!Objects.equals(userBaseDO.getPassword(), digestPassword), "密码错误");

        UserDTO userDTO = new UserDTO();
        userDTO.setId(userBaseDO.getId());
        userDTO.setUsername(userBaseDO.getUsername());
        return userDTO;
    }

    /**
     * 通过账号获取用户信息
     * */
    @Override
    public UserBaseDO getUserBaseDO(String userName) {

        UserBaseDO userBaseDO = null;
        String key = RedisConstant.USERNAME_PREFIX + userName;
        Object value = redisManager.keyValue().get(key);
        if (value instanceof UserBaseDO) {
            userBaseDO = JSON.parseObject(JSON.toJSONString(value), UserBaseDO.class);
        }
        if (Objects.isNull(userBaseDO)) {
            userBaseDO = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                    .eq(UserBaseDO::getUsername, userName)
                    .eq(UserBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                    .one();
            KingHoodExceptionUtil.isNull(userBaseDO, "用户不存在");
            redisService.cacheUser(userName,userBaseDO);
        }
        return userBaseDO;
    }

    @Override
    public UserBaseDO addUser(@Valid AddUserReqDTO in) {
        if(StringUtils.isBlank(in.getUsername())){
            in.setUsername(in.getMobile());
        }
        Long count = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(UserBaseDO::getUsername, in.getUsername())
                .eq(UserBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .count();
        KingHoodExceptionUtil.trueThrows(count > 0, "账号已经存在");

        UserBaseDO one = new UserBaseDO();
        BeanUtils.copyProperties(in, one);
        Date now = new Date();
        one.setCreateTime(now);
        one.setUpdateTime(now);
        one.setCreateUserId(UserUtil.getUserId());
        one.setUpdateUserId(UserUtil.getUserId());
        one.setId(IdGenUtil.get().nextId());
        if(Objects.nonNull(one.getPassword())){
            one.setPassword(MD5.create().digestHex16(one.getPassword()));
        }
        this.save(one);

        if(!CollectionUtils.isEmpty(in.getOrganizationIdList())){
            saveUserOrganizationBatch(in.getOrganizationIdList(), one, now);
        }

        if(!CollectionUtils.isEmpty(in.getRoleIdList())){
            saveUserRoleBatch(in.getRoleIdList(), one, now);
        }

        log.info("新增用户：{}，操作人：{}", in, UserUtil.getUser());

        redisService.cacheUser(one.getUsername(),one);

        return one;
    }

    private void saveUserOrganizationBatch(List<Long> organizationIdList, UserBaseDO one, Date now) {

        List<AuthorityUserOrganizationRelateDO> userOrganizationRelateDOList = organizationIdList.stream().map(x -> {
            AuthorityUserOrganizationRelateDO r = new AuthorityUserOrganizationRelateDO();
            r.setUserId(one.getId());
            r.setOrganizationId(x);
            r.setCreateTime(now);
            r.setUpdateTime(now);
            r.setCreateUserId(UserUtil.getUserId());
            r.setId(IdGenUtil.get().nextId());
            return r;
        }).collect(Collectors.toList());

        userOrganizationRelateService.saveBatch(userOrganizationRelateDOList);
    }

    private void saveUserRoleBatch(List<Long> roleIdList, UserBaseDO one, Date now) {

        List<AuthorityUserRoleRelateDO> userRoleRelateDOList = roleIdList.stream().map(x -> {
            AuthorityUserRoleRelateDO r = new AuthorityUserRoleRelateDO();
            r.setUserId(one.getId());
            r.setRoleId(x);
            r.setCreateTime(now);
            r.setUpdateTime(now);
            r.setCreateUserId(UserUtil.getUserId());
            r.setId(IdGenUtil.get().nextId());
            return r;
        }).collect(Collectors.toList());

        userRoleRelateService.saveBatch(userRoleRelateDOList);
    }

    @Override
    public GetUserVO getUser(Long userId) {

        return this.getBaseMapper().getUser(userId);
    }

    @Override
    public UserBaseDO updateUser(@Valid UpdateUserReqDTO in) {
        UserBaseDO one = getUser(in.getId());
        KingHoodExceptionUtil.isNull(one, "用户不存在");

        // 清理缓存
        redisService.removeUser(one.getUsername(),in.getId());

        BeanUtils.copyProperties(in, one);
        Date now = new Date();
        one.setUpdateTime(now);
        one.setUpdateUserId(UserUtil.getUserId());
        if(Objects.nonNull(one.getPassword())){
            one.setPassword(MD5.create().digestHex16(one.getPassword()));
        }
        this.updateById(one);

        new LambdaUpdateChainWrapper<>(userOrganizationRelateService.getBaseMapper())
                .eq(AuthorityUserOrganizationRelateDO::getUserId,one.getId())
                .remove();
        if(!CollectionUtils.isEmpty(in.getOrganizationIdList())){
            saveUserOrganizationBatch(in.getOrganizationIdList(), one, now);
        }

        new LambdaUpdateChainWrapper<>(userRoleRelateService.getBaseMapper())
                .eq(AuthorityUserRoleRelateDO::getUserId,one.getId())
                .remove();
        if(!CollectionUtils.isEmpty(in.getRoleIdList())){
            saveUserRoleBatch(in.getRoleIdList(), one, now);
        }

        log.info("修改api：{}，操作人：{}", in, UserUtil.getUser());
        return one;
    }

    @Override
    public Boolean deleteUser(List<Long> idList) {
        KingHoodExceptionUtil.isEmpty(idList, "请选择要删除的人员");

        UserDTO user = UserUtil.getUser();
        boolean update = new LambdaUpdateChainWrapper<>(this.getBaseMapper())
                .in(UserBaseDO::getId, idList)
                .set(UserBaseDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(UserBaseDO::getUpdateUserId, UserUtil.getUserId())
                .set(UserBaseDO::getUpdateTime, new Date())
                .update();

        log.info("删除人员：{}，结果：{}，操作人：{}", idList, update, user);

        // 清理缓存
        idList.forEach(id->redisService.removeUser(null,id));

        // 删除人员等token自动过期，如果需要及时性，可以通过用户id记录，在登录token校验的地方做一次用户id的校验
        return update;
    }

    @Override
    public List<UserBaseDO> getList(String name) {

        return new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(StringUtils.isNotBlank(name), UserBaseDO::getUsername, name)
                .eq(UserBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(UserBaseDO::getStatus, CommonConstants.ENABLE)
                .orderByAsc(UserBaseDO::getCreateTime)
                .list();
    }

    @Override
    public AuthByUserDTO getAuth(Long userId) {

        AuthByUserDTO auth = null;
        String key = RedisConstant.AUTH_PREFIX + userId;
//        Object value = null;
        Object value = redisManager.getHashOps().get(RedisConstant.AUTH,key);
        if (value instanceof UserBaseDO) {
            auth = JSON.parseObject(JSON.toJSONString(value), AuthByUserDTO.class);
        }
        if (Objects.isNull(auth)) {
            auth = this.getBaseMapper().getAuth(userId);
            if(Objects.nonNull(auth)){
                redisManager.<AuthByUserDTO>getHashOps().put(RedisConstant.AUTH,key,auth);
                // 刷新缓存时间
                redisManager.<AuthByUserDTO>template().expire(RedisConstant.AUTH,baseProperties.getTableCacheTime(), TimeUnit.SECONDS);
            }
        }
        return auth;
    }

    /**
     * 按ID获取用户
     *
     * @param ids ids
     * @author jp
     * @date 2024/01/05
     */
    @Override
    public Map<Long, UserRemoteVo> getUserByIds(List<Long> ids) {
        List<UserRemoteVo> list = this.baseMapper.getUserByIds(ids);
        Map<Long, UserRemoteVo> userMap = list.stream().collect(Collectors.toMap(UserRemoteVo::getId, i -> i, (x, y) -> x));
        return userMap;
    }

    /**
     * 按姓名或帐户获取id列表
     *
     * @param key 钥匙
     * @return @return {@link List }<{@link Long }>
     * @author jp
     * @date 2024/01/10 17:17
     */
    @Override
    public List<Long> getIdListByNameOrAccount(String key) {
        return this.baseMapper.getIdListByNameOrAccount(key);
    }

    /**
     * 用户菜单列表
     *
     * @param userId 用户id
     * @return @return {@link List }<{@link String }>
     * @author jp
     * @date 2024/01/15 14:11
     */
    @Override
    public List<String> userMenuList(Long userId) {
        return this.baseMapper.userMenuList(userId);
    }
}
